﻿using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading;
using CSVideoUploader.Http;
using CSVideoUploader.Util;
using System;
using System.Text;

namespace CSVideoUploader.Client.Xina
{
    /// <summary>
    /// 渣浪客户端类子类
    /// 实现利用标准接口上传
    /// </summary>
    class NormalXinaClient : XinaClient
    {
        #region 接口URL
        /// <summary>获取hach的地址</summary>
        const string HACH_URL = "http://vupload.you.video.sina.com.cn/u.php?m=1";
        /// <summary>提交视频文件的地址</summary>
        const string UPLOAD_URL = "http://vupload.you.video.sina.com.cn/cgi-bin/post_utf8_vip.cgi?";
        /// <summary>监视上传进度的地址</summary>
        const string HANDLE_URL = "http://vupload.you.video.sina.com.cn/cgi-bin/handle_utf8.cgi";
        /// <summary>不知道用途但是有必要访问的URL之1</summary>
        const string UNKNOWN1_URL = "http://control.video.sina.com.cn/useradmin/topicsset/getUserSpecial.php?page=1&pagesize=6&callback=&random=";
        /// <summary>提交视频信息的地址</summary>
        const string COMMIT_URL = "http://vupload.you.video.sina.com.cn/upload_com_utf8.php";
        /// <summary>不知道用途但是有必要访问的URL之2</summary>
        const string UNKNOWN2_URL = "http://you.video.sina.com.cn/upload_succ.php?topicid=&m=1";
        #endregion

        public NormalXinaClient(string username)
            : base(username)
        {}

        public override void Upload(XinaUploadTask task, Http.IUploadProgressListener listener)
        {
            try
            {
                // 获取hach
                string hach = GetHach();
                // 上传文件，获取在服务器存储的名称
                string retName = UploadAndHandle(hach, task.FileName, listener);
                // 提交信息
                string vid = CommitInfo(retName, task);

                // 输出日志
                Logger.Info("上传完成！VID => " + vid);
            }
            catch (Exception e)
            {
                // 输出错误信息
                Console.Error.Write(e.StackTrace);
            }

        }

        /// <summary>
        /// 获取hach
        /// </summary>
        /// <returns></returns>
        private string GetHach()
        {
            string hach = null;

            // 读取网页
            string body = client.Get(HACH_URL);
            // 匹配hach值
            Regex regex = new Regex("showUploadFlash\\(\\'[\\w]+\\'\\)");
            Match m = regex.Match(body);
            if (m.Success)
            {
                hach = m.Value;
                hach = hach.Substring(17, hach.Length - 19);
                Logger.Debug("hach => " + hach);
            }
            else
            {
                throw new Exception("获取Hach失败！");
            }

            return hach;
        }

        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="hach">hach值，必须</param>
        /// <param name="fileName">文件名</param>
        /// <param name="listener">监听器</param>
        /// <returns></returns>
        private string UploadAndHandle(string hach, string fileName, IUploadProgressListener listener)
        {
            // 准备上传文件必须的参数
            string uploadURL = UPLOAD_URL + hach;
            Dictionary<string, string> uploadParams = new Dictionary<string, string>();
            uploadParams.Add("Upload", "Submit Query");
            // 启动独立的线程上传文件
            NormalUploadThread thread = new NormalUploadThread(uploadURL, uploadParams, "video", fileName, listener);
            thread.Start();

            // 在当前线程中指定handle
            StringBuilder handleURL = new StringBuilder();
            handleURL.Append(HANDLE_URL)
                .Append("?hach=").Append(hach)
                .Append("&random=").Append(DateTime.Now.ToBinary());
            string body = client.Get(handleURL.ToString());

            // 等待上传线程完成
            thread.Wait();

            return PickRetName(body);
        }

        /// <summary>
        /// 获取服务器端的文件存储名
        /// </summary>
        /// <param name="body"></param>
        /// <returns></returns>
        private string PickRetName(string body)
        {
            string retName = null;

            Regex regex = new Regex(@"showOK\('.*?'\)");
            Match m = regex.Match(body);
            if (m.Success)
            {
                retName = m.Value;
                retName = retName.Substring(8, retName.Length - 10);
            }
            else
            {
                throw new Exception("无法获取服务器端保存名称！");
            }

            return retName;
        }

        /// <summary>
        /// 提交视频信息
        /// </summary>
        /// <param name="retName"></param>
        /// <param name="task"></param>
        /// <returns></returns>
        private string CommitInfo(string retName, XinaUploadTask task)
        {
            // 提交前需要访问一个URL
            StringBuilder buf = new StringBuilder();
            buf.Append(UNKNOWN1_URL).Append(DateTime.Now.ToBinary());
            client.Get(buf.ToString());

            // 提交信息
            Dictionary<string, string> infoParams = new Dictionary<string, string>();
            infoParams.Add("attRetName", retName);
            infoParams.Add("expClose", "0");
            infoParams.Add("src_type", "400");
            infoParams.Add("url", "");
            infoParams.Add("m", "1");
            infoParams.Add("title", task.Title);
            infoParams.Add("description", task.Description);
            infoParams.Add("tags", task.GetTagsText());
            infoParams.Add("channel", task.Channal);
            infoParams.Add("channel_text", task.GetChannalText());
            infoParams.Add("froms", task.From);
            infoParams.Add("special", "");
            infoParams.Add("special_text_all", "");
            infoParams.Add("special_text", "------");
            string body = client.Post(COMMIT_URL, infoParams);
            VideoAndUserInfo info = PickVideoAndUserInfo(body);

            // 获取后再需要访问一个URL
            buf = new StringBuilder();
            buf.Append(UNKNOWN2_URL)
                .Append("&videoid=").Append(info.VideoID)
                .Append("&userid=").Append(info.UserID);
            client.Get(buf.ToString());

            return info.VideoID;
        }

        /// <summary>
        /// 获取视频和用户的身份信息
        /// </summary>
        /// <param name="body"></param>
        /// <returns></returns>
        private VideoAndUserInfo PickVideoAndUserInfo(string body)
        {
            VideoAndUserInfo info = new VideoAndUserInfo();

            Regex regex = new Regex(@"parent.uploadSucc\(""\d+"",\s*""\d+""\)");
            Match m = regex.Match(body);
            if (m.Success)
            {
                string str = m.Value.Substring(18, m.Value.Length - 19);

                int pos = str.IndexOf(',');
                info.VideoID = str.Substring(0, pos).Trim();
                info.VideoID = info.VideoID.Substring(1, info.VideoID.Length - 2);
                info.UserID = str.Substring(pos + 1, str.Length - pos - 1).Trim();
                info.UserID = info.UserID.Substring(1, info.UserID.Length - 2);
            }
            return info;
        }
    }

    /// <summary>
    /// 普通上传线程类
    /// </summary>
    private class NormalUploadThread
    {
        #region 线程同步相关属性
        /// <summary>是否执行完成</summary>
        bool bIsFinish = false;
        /// <summary>等待执行完成的Event</summary>
        EventWaitHandle handler = null;
        #endregion

        #region 上传相关属性
        /// <summary>目标地址</summary>
        private string url = null;
        /// <summary>参数</summary>
        private Dictionary<string, string> parameters = null;
        /// <summary>文件字段名称</summary>
        private string fileFieldName = null;
        /// <summary>文件流</summary>
        private FileStream file = null;
        /// <summary>进度监听</summary>
        private IUploadProgressListener listener = null;
        #endregion

        public NormalUploadThread(string url, Dictionary<string, string> parameters,
            string fileFieldName, string fileName, IUploadProgressListener listener)
        {
            this.url = url;
            this.parameters = parameters;
            this.fileFieldName = fileFieldName;
            this.file = new FileStream(fileName, FileMode.Open, FileAccess.Read);
            this.listener = listener;
        }

        public void Start()
        {
            Thread thread = new Thread(new ThreadStart(this.Lifecycle));
            thread.Start();
        }

        public void Wait()
        {
            if (!bIsFinish)
                handler.WaitOne();
        }

        private void Lifecycle()
        {
            // 初始化事件对象
            handler = new ManualResetEvent(false);
            // 设置开始标记
            bIsFinish = false;

            HttpClient client = new HttpClient("GB2312");
            // 发送文件
            client.PostFile(url, parameters, fileFieldName, file, listener);

            // 设置完成标记
            bIsFinish = true;
            // 通知事件对象
            handler.Set();
        }
    }

    struct VideoAndUserInfo
    {
        public string VideoID;
        public string UserID;
    }
}
